home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / rhinosrc.lha / hop.c < prev    next >
C/C++ Source or Header  |  1993-05-22  |  10KB  |  421 lines

  1. /*
  2.  *    HOP.C    -- trace route packets take to a remote host
  3.  *
  4.  *    02-90    -- Katie Stevens (dkstevens@ucdavis.edu)
  5.  *           UC Davis, Computing Services
  6.  *           Davis, CA
  7.  *    04-90    -- Modified by Phil Karn to use raw IP sockets to read replies
  8.  *    08-90    -- Modified by Bill Simpson to display domain names
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <fcntl.h>    /* for close() */
  13. #include <string.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "usock.h"
  17. #include "socket.h"
  18. #include "session.h"
  19. #include "timer.h"
  20. #include "proc.h"
  21. #include "netuser.h"
  22. #include "domain.h"
  23. #include "commands.h"
  24. #include "tty.h"
  25. #include "cmdparse.h"
  26. #include "ip.h"
  27. #include "icmp.h"
  28. #include "udp.h"
  29. #include "hardware.h"
  30.  
  31. #define HOPMAXQUERY    5        /* Max# queries each TTL value */
  32. static int16 Hoprport = 32768+666;    /* funny port for udp probes */
  33. #define HOP_HIGHBIT    32768        /* Mask to check ICMP msgs */
  34.  
  35.  
  36. #define HOPTRACE    1        /* Enable HOP tracing */
  37. #ifdef HOPTRACE
  38. static int Hoptrace = 0;
  39. static int hoptrace __ARGS((int argc,char *argv[],void *p));
  40. #endif
  41.  
  42.  
  43. static unsigned  short Hopmaxttl  = 30;     /* max attempts */
  44. static unsigned  short Hopmaxwait = 5;        /* secs timeout each attempt */
  45. static unsigned  short Hopquery   = 3;        /* #probes each attempt */
  46.  
  47. static int hopcheck __ARGS((int argc,char *argv[],void *p));
  48. static int hopttl __ARGS((int argc,char *argv[],void *p));
  49. static int hopwait __ARGS((int argc,char *argv[],void *p));
  50. static int hopnum __ARGS((int argc,char *argv[],void *p));
  51. static int geticmp __ARGS((int s,int16 lport,int16 fport,
  52.     int32 *sender,char *type,char *code));
  53.  
  54. static struct cmds Hopcmds[] = {
  55.  
  56.     "check",        hopcheck,       2048,   2,      "check <host>",
  57.     "maxttl",       hopttl,         0,      0,      NULLCHAR,
  58.     "maxwait",      hopwait,        0,      0,      NULLCHAR,
  59.     "queries",      hopnum,         0,      0,      NULLCHAR,
  60. #ifdef HOPTRACE
  61.     "trace",        hoptrace,       0,      0,      NULLCHAR,
  62. #endif
  63.     NULLCHAR,
  64. };
  65.  
  66. /* attempt to trace route to a remote host */
  67. int
  68. dohop(argc,argv,p)
  69. int argc;
  70. char *argv[];
  71. void *p;
  72. {
  73.     return subcmd(Hopcmds,argc,argv,p);
  74. }
  75.  
  76. /* Set/show # queries sent each TTL value */
  77. static int
  78. hopnum(argc,argv,p)
  79. int argc;
  80. char *argv[];
  81. void *p;
  82. {
  83.     int16 r;
  84.     int16 x = Hopquery;
  85.     r = setshort(&x,"# queries each attempt",argc,argv);
  86.     if ((x <= 0)||(x > HOPMAXQUERY)) {
  87.         printf("Must be  0 < x <= %d\n",HOPMAXQUERY);
  88.         return 0;
  89.     } else {
  90.         Hopquery = x;
  91.     }
  92.     return (int)r;
  93. }
  94. #ifdef HOPTRACE
  95. /* Set/show tracelevel */
  96. static int
  97. hoptrace(argc,argv,p)
  98. int argc;
  99. char *argv[];
  100. void *p;
  101. {
  102.     return setbool(&Hoptrace,"HOPCHECK tracing",argc,argv);
  103. }
  104. #endif
  105. /* Set/show maximum TTL value for a traceroute query */
  106. static int
  107. hopttl(argc,argv,p)
  108. int argc;
  109. char *argv[];
  110. void *p;
  111. {
  112.     int16 r;
  113.     int16 x = Hopmaxttl;
  114.     r = setshort(&x,"Max attempts to reach host",argc,argv);
  115.     if ((x <= 0)||(x > 255)) {
  116.         printf("Must be  0 < x <= 255\n");
  117.         return 0;
  118.     } else {
  119.         Hopmaxttl = x;
  120.     }
  121.     return (int)r;
  122. }
  123. /* Set/show #secs until timeout for a traceroute query */
  124. static int
  125. hopwait(argc,argv,p)
  126. int argc;
  127. char *argv[];
  128. void *p;
  129. {
  130.     int16 r;
  131.     int16 x = Hopmaxwait;
  132.     r = setshort(&x,"# secs to wait for reply to query",argc,argv);
  133.     if (x <= 0) {
  134.         printf("Must be >= 0\n");
  135.         return 0;
  136.     } else {
  137.         Hopmaxwait = x;
  138.     }
  139.     return (int)r;
  140. }
  141.  
  142. /* send probes to trace route of a remote host */
  143. static int
  144. hopcheck(argc,argv,p)
  145. int argc;
  146. char *argv[];
  147. void *p;
  148. {
  149.     struct session *sp;        /* Session for trace output */
  150.     int s;                /* Socket for queries */
  151.     int s1;             /* Raw socket for replies */
  152.     struct socket lsocket;        /* Local socket sending queries */
  153.     struct socket rsocket;        /* Final destination of queries */
  154.     int32 cticks;            /* Timer for query replies */
  155.     int32 icsource;         /* Sender of last ICMP reply */
  156.     char ictype;            /* ICMP type last ICMP reply */
  157.     char iccode;            /* ICMP code last ICMP reply */
  158.     int32 lastaddr;         /* Sender of previous ICMP reply */
  159.     struct sockaddr_in sock;
  160.     register struct usock *usp;
  161.     register struct sockaddr_in *sinp;
  162.     unsigned char sndttl, q;
  163.     int tracedone = 0;
  164.     int ilookup = 1;        /* Control of inverse domain lookup */
  165.     int c;
  166.     extern int optind;
  167.     char *hostname;
  168.     int save_trace;
  169.  
  170.     optind = 1;
  171.     while((c = getopt(argc,argv,"n")) != EOF){
  172.         switch(c){
  173.         case 'n':
  174.             ilookup = 0;
  175.             break;
  176.         }
  177.     }
  178.     hostname = argv[optind];
  179.     /* Allocate a session descriptor */
  180.     if((sp = newsession(hostname,HOP,1)) == NULLSESSION){
  181.         printf("Too many sessions\n");
  182.         keywait(NULLCHAR,1);
  183.         return 1;
  184.     }
  185.     s = -1;
  186.  
  187.     /* Setup UDP socket to remote host */
  188.     sock.sin_family = AF_INET;
  189.     sock.sin_port = Hoprport;
  190.     printf("Resolving %s... ",hostname);
  191.     if((sock.sin_addr.s_addr = resolve(hostname)) == 0){
  192.         printf("Host %s unknown\n",hostname);
  193.         keywait(NULLCHAR,1);
  194.         freesession(sp);
  195.         return 1;
  196.     }
  197.  
  198.     /* Open socket to remote host */
  199.     printf("traceroute to %s\n",psocket((struct sockaddr *)&sock));
  200.     if((s = socket(AF_INET,SOCK_DGRAM,0)) == -1){
  201.         printf("Can't create udp socket\n");
  202.         keywait(NULLCHAR,1);
  203.         freesession(sp);
  204.         return 1;
  205.     }
  206.     if(connect(s,(char *)&sock,sizeof(sock)) == -1){
  207.         printf("Connect failed\n");
  208.         keywait(NULLCHAR,1);
  209.         freesession(sp);
  210.         return 1;
  211.     }
  212.     if((s1 = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) == -1){
  213.         printf("Can't create raw socket\n");
  214.         keywait(NULLCHAR,1);
  215.         close(s);
  216.         freesession(sp);
  217.         return 1;
  218.     }
  219.     /* turn off icmp tracing while hop-checking */
  220.     save_trace = Icmp_trace;
  221.     Icmp_trace = 0;
  222.  
  223.     /* Setup structures to send queries */
  224.     /* Retrieve socket details for user socket control block */
  225.     usp = itop(s);
  226.     sinp = (struct sockaddr_in *)usp->name;
  227.     lsocket.address = sinp->sin_addr.s_addr;
  228.     lsocket.port = sinp->sin_port;
  229.     sinp = (struct sockaddr_in *)usp->peername;
  230.     rsocket.address = sinp->sin_addr.s_addr;
  231.  
  232.     /* Send queries with increasing TTL; start with TTL=1 */
  233.     if (Hoptrace)
  234.         log(s,"HOPCHECK start trace to %s\n",sp->name);
  235.     for (sndttl=1; (sndttl < Hopmaxttl); ++sndttl, sinp->sin_port++) {
  236.         /* Increment funny UDP port number each round */
  237.         rsocket.port = sinp->sin_port;
  238.         printf("%3d:",sndttl);
  239.         lastaddr = (int32)0;
  240.         /* Send a round of queries */
  241.         for (q=0; (q < Hopquery); ++q) {
  242.             send_udp(&lsocket,&rsocket,0,sndttl,NULLBUF,0,0,0);
  243.             cticks = msclock();
  244.             alarm( ((long)Hopmaxwait*1000L) );
  245.  
  246.             /* Wait for a reply to our query */
  247.             if(geticmp(s1,lsocket.port,rsocket.port,
  248.              &icsource,&ictype,&iccode) == -1){
  249.                 if(errno != EALARM)
  250.                     goto done;    /* User reset */
  251.                 /* Alarm rang, give up waiting for replies */
  252.                 printf(" ***");
  253.                 continue;
  254.             }
  255.             /* Save #ticks taken for reply */
  256.             cticks = msclock() - cticks;
  257.             /* Report ICMP reply */
  258.             if (icsource != lastaddr) {
  259.                 struct rr *save_rrlp, *rrlp;
  260.  
  261.                 if(lastaddr != (int32)0)
  262.                     printf("\n    ");
  263.                 printf(" %-15s",inet_ntoa(icsource));
  264.                 if(ilookup){
  265.                     for(rrlp = save_rrlp = inverse_a(icsource);
  266.                         rrlp != NULLRR;
  267.                         rrlp = rrlp->next){
  268.                         if(rrlp->rdlength > 0){
  269.                             switch(rrlp->type){
  270.                             case TYPE_PTR:
  271.                                 printf(" %s", rrlp->rdata.name);
  272.                                 goto got_name;
  273.                             case TYPE_A:
  274.                                 printf(" %s", rrlp->name);
  275.                                 goto got_name;
  276.                             }
  277. #ifdef notdef
  278.                             if(rrlp->next != NULLRR)
  279.                                 printf("\n%20s"," ");
  280. #endif
  281.                         }
  282.                     }
  283.                     got_name: ;
  284.                     free_rr(save_rrlp);
  285.  
  286.                 }
  287.                 lastaddr = icsource;
  288.             }
  289.             printf(" (%ld ms)",cticks);
  290. #ifdef HOPTRACE
  291.             if (Hoptrace)
  292.                 log(s,
  293.                     "(hopcheck) ICMP from %s (%ldms) %s %s",
  294.                     inet_ntoa(icsource),
  295.                     cticks,
  296.                     Icmptypes[ictype],
  297.                     ((ictype == ICMP_TIME_EXCEED)?Exceed[iccode]:Unreach[iccode]));
  298. #endif
  299.  
  300.             /* Check type of reply */
  301.             if (ictype == ICMP_TIME_EXCEED)
  302.                 continue;
  303.             /* Reply was: destination unreachable */
  304.             switch(iccode) {
  305.             case ICMP_PORT_UNREACH:
  306.                 ++tracedone;
  307.                 break;
  308.             case ICMP_NET_UNREACH:
  309.                 ++tracedone;
  310.                 printf(" !N");
  311.                 break;
  312.             case ICMP_HOST_UNREACH:
  313.                 ++tracedone;
  314.                 printf(" !H");
  315.                 break;
  316.             case ICMP_PROT_UNREACH:
  317.                 ++tracedone;
  318.                 printf(" !P");
  319.                 break;
  320.             case ICMP_FRAG_NEEDED:
  321.                 ++tracedone;
  322.                 printf(" !F");
  323.                 break;
  324.             case ICMP_ROUTE_FAIL:
  325.                 ++tracedone;
  326.                 printf(" !S");
  327.                 break;
  328.             case ICMP_ADMIN_PROHIB:
  329.                 ++tracedone;
  330.                 printf(" !A");
  331.                 break;
  332.             default:
  333.                 printf(" !?");
  334.                 break;
  335.             }
  336.         }
  337.         /* Done with this round of queries */
  338.         alarm((long)0);
  339.         printf("\n");
  340.         /* Check if we reached remote host this round */
  341.         if (tracedone != 0)
  342.             break;
  343.     }
  344.  
  345.     /* Done with traceroute */
  346. done:    close(s);
  347.     s = -1;
  348.     close(s1);
  349.     printf("traceroute done: ");
  350.     Icmp_trace = save_trace;
  351.     if (sndttl >= Hopmaxttl) {
  352.         printf("!! maximum TTL exceeded\n");
  353.     } else if ((icsource == rsocket.address)
  354.             &&(iccode == ICMP_PORT_UNREACH)) {
  355.         printf("normal (%s %s)\n",
  356.             Icmptypes[ictype],Unreach[iccode]);
  357.     } else {
  358.         printf("!! %s %s\n",
  359.             Icmptypes[ictype],Unreach[iccode]);
  360.     }
  361. #ifdef HOPTRACE
  362.     if (Hoptrace)
  363.         log(s,"HOPCHECK to %s done",sp->name);
  364. #endif
  365.     keywait(NULLCHAR,1);
  366.     freesession(sp);
  367.     return 0;
  368. }
  369.  
  370. /* Read raw network socket looking for ICMP messages in response to our
  371.  * UDP probes
  372.  */
  373. static int
  374. geticmp(s,lport,fport,sender,type,code)
  375. int s;
  376. int16 lport;
  377. int16 fport;
  378. int32 *sender;
  379. char *type,*code;
  380. {
  381.     int size;
  382.     struct icmp icmphdr;
  383.     struct ip iphdr;
  384.     struct udp udphdr;
  385.     struct mbuf *bp;
  386.     struct sockaddr_in sock;
  387.  
  388.     for(;;){
  389.         size = sizeof(sock);
  390.         if(recv_mbuf(s,&bp,0,(char *)&sock,&size) == -1)
  391.             return -1;
  392.         /* It's an ICMP message, let's see if it's interesting */
  393.         ntohicmp(&icmphdr,&bp);
  394.         if((icmphdr.type != ICMP_TIME_EXCEED ||
  395.          icmphdr.code != ICMP_TTL_EXCEED)
  396.          && icmphdr.type != ICMP_DEST_UNREACH){
  397.             /* We're not interested in these */
  398.             free_p(bp);
  399.             continue;
  400.         }
  401.         ntohip(&iphdr,&bp);
  402.         if(iphdr.protocol != UDP_PTCL){
  403.             /* Not UDP, so can't be interesting */
  404.             free_p(bp);
  405.             continue;
  406.         }
  407.         ntohudp(&udphdr,&bp);
  408.         if(udphdr.dest != fport || udphdr.source != lport){
  409.             /* Not from our hopcheck session */
  410.             free_p(bp);
  411.             continue;
  412.         }
  413.         /* Passed all of our checks, so return it */
  414.         *sender = sock.sin_addr.s_addr;
  415.         *type = icmphdr.type;
  416.         *code = icmphdr.code;
  417.         free_p(bp);
  418.         return 0;
  419.     }
  420. }
  421.